package atom.core3.hibernate.dao.impl;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;

import atom.core0.exception.BizException;
import atom.core0.j2ee.page.PageResult;
import atom.core0.util.ObjectConvert;
import atom.core1.object.CopyUtil;
import atom.core1.util.Map2BeanUtil;
import atom.core3.hibernate.util.QueryHelper;

/**
 * @ClassName: BaseDao
 * @Description: baseDao实现
 * @author hike 注意：所有的参数不能是null
 * @date 2014年6月16日17:09:52
 * 
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public abstract class BaseHibernateDao {

	private static Logger log = Logger.getLogger(BaseHibernateDao.class);
	// 必须注入sessionFactory
	@Resource(name = "sessionFactory")
	// @Autowired
	private SessionFactory sessionFactory;

	// protected Class entityClass;

	public BaseHibernateDao() {

	}

	// protected Class getEntityClass() {
	// if (entityClass == null) {
	// entityClass = (Class) ((ParameterizedType)
	// getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	// }
	// return entityClass;
	// }
	abstract protected Class getEntityClass();

	/**
	 * <保存实体> <完整保存实体>
	 * 
	 * @param t
	 *            实体参数
	 */
	public void insert(Serializable t) {
		this.getSession().save(t);
	}

	/**
	 * <保存或者更新实体>
	 * 
	 * @param t
	 *            实体
	 */
	public void saveOrUpdate(Serializable t) {
		this.getSession().saveOrUpdate(t);
	}

	public void saveOrUpdateAll(Collection entities) {

		// 从源码看，hibernate
		// 的saveOrUpdateAll方法是针对每一个对象的保存/更新都开启和关闭事务，这对大量数据操作存在一定的效率问题.
		// 因此hibernate4删除了
		for (Object element : entities) {
			this.getSession().saveOrUpdate(element);
		}
	}

	/**
	 * <update>
	 * 
	 * @param t
	 *            实体
	 */
	public void update(Object t) {
		this.getSession().update(t);
	}

	public void merge(Object entity) {
		this.getSession().merge(entity);
	}

	/**
	 * <get> <查找的get方法>
	 * 
	 * @param id
	 *            实体的id
	 * @return 查询出来的实体
	 * @see com.itv.launcher.util.IBaseDao#get(java.io.Serializable)
	 */
	public Object findById(Serializable id) {
		if (id == null) {
			return null;
		}
		Object load = this.getSession().get(getEntityClass(), id);
		return load;
	}

	public Object findByIdWithLock(Serializable id) {
		if (id == null) {
			return null;
		}
		return this.getSession().get(getEntityClass(), id, LockOptions.UPGRADE);
	}

	public Object findByIdWithLock(Class model, Serializable id, boolean wait) {
		if (id == null) {
			return null;
		}

		LockMode mode = wait ? LockMode.PESSIMISTIC_WRITE : LockMode.UPGRADE_NOWAIT;// LockMode.UPGRADE
																					// LockMode.UPGRADE_NOWAIT

		return this.getSession().get(getEntityClass(), id, mode);
	}

	/**
	 * <delete> <删除表中的t数据>
	 * 
	 * @param t
	 *            实体
	 */
	public void delete(Object t) {
		this.getSession().delete(t);
	}

	/**
	 * <根据ID删除数据>
	 * 
	 * @param Id
	 *            实体id
	 * @return 是否删除成功
	 */
	public boolean deleteById(Serializable Id) {
		Object t = findById(Id);
		if (t == null) {
			return false;
		}
		delete(t);
		return true;
	}

	/**
	 * <删除所有>
	 * 
	 * @param entities
	 *            实体的Collection集合
	 */
	public void deleteAll(Collection entities) {
		for (Object entity : entities) {
			this.getSession().delete(entity);
		}
	}

	public List findAll() {
		QueryHelper helper = new QueryHelper(getEntityClass());
		return getList(helper);
	}

	/**
	 * <根据HQL语句，得到对应的list>
	 * 
	 * @param hqlString
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询多个实体的List集合
	 */
	public List getList(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	/**
	 * description: 查询.
	 * 
	 * @param helper
	 * @return
	 * 
	 * @author zhaomc
	 * @since 2007-12-03
	 */
	public List getList(final QueryHelper helper) {
		Query query = helper.createQuery(this.getSession());
		return query.list();
	}

	// 位置参数
	public List getList(String hqlString, List params) {
		Query query = this.getSession().createQuery(hqlString);
		if (params != null)
			query.setParameters(params.toArray(), getParamTypes(params));
		return query.list();
	}

	// 有名参数
	public List getList(String hqlString, Map param) {
		Query query = this.getSession().createQuery(hqlString);
		if (param != null) {
			Iterator it = param.entrySet().iterator();
			while (it.hasNext()) {
				Map.Entry entry = (Map.Entry) it.next();
				String key = (String) entry.getKey();
				Object value = entry.getValue();
				query.setParameter(key, value);
			}
		}
		return query.list();
	}

	/**
	 * 加锁查询.
	 * 
	 * @param helper
	 * @param alias
	 * @param lockMode
	 * @return
	 */
	protected List getList(final QueryHelper helper, final String alias, final LockMode lockMode) {
		Query query = helper.createQuery(this.getSession());
		query.setLockMode(alias, lockMode);
		return query.list();
	}

	/**
	 * <根据SQL语句，得到对应的list>
	 * 
	 * @param sqlString
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询多个实体的List集合
	 */
	public List getListBySql(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.list();
	}

	public List getListBySql(final QueryHelper helper, Class beanclass) {
		if (beanclass == null) {
			Query query = helper.createSQLQuery(this.getSession());
			return query.list();
		} else {
			Query query = helper.createSQLQuery(this.getSession());
			List maplist = query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
			try {
				List listresult = Map2BeanUtil.transListMap2ListBeanIgnoreCase(maplist, beanclass, null);
				return listresult;
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				return null;
			}
		}

	}

	public List getListBySql(final QueryHelper helper, final ResultTransformer transformer) {
		Query query = helper.createSQLQuery(this.getSession());
		return query.setResultTransformer(transformer).list();
	}

	/**
	 * <执行Hql语句>
	 * 
	 * @param hqlString
	 *            hql
	 * @param values
	 *            不定参数数组
	 */
	public int execute(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.executeUpdate();
	}

	public int execute(QueryHelper helper) {

		Query query = helper.createQuery(this.getSession());
		return query.executeUpdate();
	}

	// 有名参数
	public int execute(String hqlString, Map param) {
		Query query = this.getSession().createQuery(hqlString);
		Iterator it = param.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String key = (String) entry.getKey();
			Object value = entry.getValue();
			query.setParameter(key, value);
		}
		return query.executeUpdate();
	}

	// 位置参数
	public int execute(String hqlString, List params) {
		Query query = this.getSession().createQuery(hqlString);
		query.setParameters(params.toArray(), getParamTypes(params));
		return query.executeUpdate();
	}

	/**
	 * <执行Sql语句>
	 * 
	 * @param sqlString
	 *            sql
	 * @param values
	 *            不定参数数组
	 */
	public int executeSql(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.executeUpdate();
	}

	public int executeSql(QueryHelper helper) {

		Query query = helper.createSQLQuery(this.getSession());
		return query.executeUpdate();
	}

	public int executeSql(String hqlString, Map param) {
		Query query = this.getSession().createSQLQuery(hqlString);
		Iterator it = param.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String key = (String) entry.getKey();
			Object value = entry.getValue();
			query.setParameter(key, value);
		}
		return query.executeUpdate();
	}

	public int executeSql(String hqlString, List params) {
		Query query = this.getSession().createSQLQuery(hqlString);
		query.setParameters(params.toArray(), getParamTypes(params));
		return query.executeUpdate();
	}

	/**
	 * <根据HQL语句查找唯一实体>
	 * 
	 * @param hqlString
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询实体
	 */
	public Object getUniqueResult(String hqlString, Object... values) {
		Query query = this.getSession().createQuery(hqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.uniqueResult();
	}

	public Object getUniqueResult(final QueryHelper helper) {
		Query query = helper.createQuery(this.getSession());
		return query.uniqueResult();

	}

	/**
	 * <根据SQL语句查找唯一实体>
	 * 
	 * @param sqlString
	 *            SQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 查询实体
	 */
	public Object getUniqueResultBySql(String sqlString, Object... values) {
		Query query = this.getSession().createSQLQuery(sqlString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query.uniqueResult();
	}

	public Object getUniqueResultBySql(final QueryHelper helper) {
		Query query = helper.createSQLQuery(this.getSession());
		return query.uniqueResult();

	}

	/**
	 * <contains>
	 * 
	 * @param t
	 *            实体
	 * @return 是否包含
	 */
	public boolean contains(Object t) {
		return this.getSession().contains(t);
	}

	public void refresh(Object t) {
		this.getSession().refresh(t);
	}

	public void flush() {
		this.getSession().flush();
	}

	public void evict(final Object entity) {
		this.getSession().evict(entity);
	}

	public void clear() {
		this.getSession().clear();
	}

	/**
	 * <根据HQL得到记录数>
	 * 
	 * @param hql
	 *            HQL语句
	 * @param values
	 *            不定参数的Object数组
	 * @return 记录总数
	 */

	public int countByHql(String hql, Object... values) {
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		Object o = query.uniqueResult();
		// 有些数据库返回的是Integer
		return ObjectConvert.Object2Int(o);
	}

	public int countByHql(QueryHelper helper) {
		Query query = helper.createQuery(this.getSession());
		Object o = query.uniqueResult();
		// 有些数据库返回的是Integer
		return ObjectConvert.Object2Int(o);

	}

	public int countBySql(String hql, Object... values) {
		Query query = this.getSession().createSQLQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		Object o = query.uniqueResult();
		return ObjectConvert.Object2Int(o);
	}

	public int countBySql(QueryHelper helper) {
		Query query = helper.createSQLQuery(this.getSession());
		Object o = query.uniqueResult();
		return ObjectConvert.Object2Int(o);
	}

	public PageResult getPageData(final QueryHelper helper, final int recordCount, final int pageSize, final int pageNumber) {
		PageResult paginater = new PageResult(recordCount, pageSize, pageNumber);

		Query query = helper.createQuery(this.getSession());
		query.setMaxResults(paginater.getPageSize()).setFirstResult((int) paginater.getOffsetIndex());
		List list = query.list();
		paginater.setData(list);

		return paginater;
	}

	public PageResult getPageDataBySql(final QueryHelper helper, final int recordCount, final int pageSize, final int pageNumber, Class beanclass) {
		PageResult paginater = new PageResult(recordCount, pageSize, pageNumber);
		Query query = helper.createSQLQuery(this.getSession());
		query.setMaxResults(paginater.getPageSize()).setFirstResult((int) paginater.getOffsetIndex());

		if (beanclass == null) {
			List list = query.list();
			paginater.setData(list);
			return paginater;
		} else {
			List maplist = query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
			try {
				List listresult = Map2BeanUtil.transListMap2ListBeanIgnoreCase(maplist, beanclass, null);
				paginater.setData(listresult);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
			return paginater;
		}
	}

	public PageResult getPageData(final QueryHelper helper, QueryHelper countHql, final int pageSize, final int pageNumber) {
		Query query = helper.createQuery(this.getSession());
		int totalCount = 0;
		if (countHql == null) {
			ScrollableResults results = query.scroll();
			results.last();
			totalCount = results.getRowNumber() + 1;// 设置总记录数
		} else {

			totalCount = countByHql(countHql);
		}
		PageResult paginater = new PageResult(totalCount, pageSize, pageNumber);

		query.setMaxResults(paginater.getPageSize());
		query.setFirstResult((int) paginater.getOffsetIndex());
		List list = query.list();
		paginater.setData(list);

		return paginater;
	}

	public PageResult getPageDataBySql(final QueryHelper helper, QueryHelper countSql, final int pageSize, final int pageNumber, Class beanclass) {
		Query query = helper.createSQLQuery(this.getSession());
		int totalCount = 0;
		if (countSql == null) {
			ScrollableResults results = query.scroll();
			results.last();
			totalCount = results.getRowNumber() + 1;// 设置总记录数
		} else {

			totalCount = countBySql(countSql);
		}
		PageResult paginater = new PageResult(totalCount, pageSize, pageNumber);

		query.setMaxResults(paginater.getPageSize());
		query.setFirstResult((int) paginater.getOffsetIndex());

		if (beanclass == null) {
			List list = query.list();
			paginater.setData(list);
			return paginater;
		}
		else
		{
			List maplist = query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
			try {
				List listresult = Map2BeanUtil.transListMap2ListBeanIgnoreCase(maplist, beanclass, null);
				paginater.setData(listresult);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
			}
			return paginater;
			
		}

	}

	/**
	 * <HQL分页查询>
	 * 
	 * @param hql
	 *            HQL语句
	 * @param countHql
	 *            查询记录条数的HQL语句
	 * @param pageNo
	 *            下一页
	 * @param pageSize
	 *            一页总条数
	 * @param values
	 *            不定Object数组参数
	 * @return PageResults的封装类，里面包含了页码的信息以及查询的数据List集合
	 */

	public PageResult getPageData(String hql, String countHql, int pageSize, int pageNo, Object... values) {
		Query query = this.getSession().createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		int currentPage = pageNo > 1 ? pageNo : 1;
		int totalCount = 0;
		if (countHql == null) {
			ScrollableResults results = query.scroll();
			results.last();
			totalCount = results.getRowNumber() + 1;// 设置总记录数
		} else {
			totalCount = countByHql(countHql, values);

		}

		PageResult retValue = new PageResult(totalCount, pageSize, currentPage);
		// retValue.resetNextPageNo();

		List itemList = query.setFirstResult(retValue.getOffsetIndex()).setMaxResults(pageSize).list();

		retValue.setData(itemList);

		return retValue;
	}

	/**
	 * @return the sessionFactory
	 */
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	/**
	 * @param sessionFactory
	 *            the sessionFactory to set
	 */
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * 
	 * @return session
	 */
	public Session getSession() {
		// 需要开启事物，才能得到CurrentSession
		Session sess ;
//		try
//		{
		sess = sessionFactory.getCurrentSession();
//		}
//		catch(Exception e)
//		{
//			sess = sessionFactory.openSession();
//
//		}
		
		return sess;
	}

	/**
	 * 
	 * 设置每行批处理参数
	 * 
	 * @param ps
	 * @param pos
	 *            ?占位符索引，从0开始
	 * @param data
	 * @throws SQLException
	 * @see [类、类#方法、类#成员]
	 */
	private void setParameter(PreparedStatement ps, int pos, Object data) throws SQLException {
		if (data == null) {
			ps.setNull(pos + 1, Types.VARCHAR);
			return;
		}
		Class dataCls = data.getClass();
		if (String.class.equals(dataCls)) {
			ps.setString(pos + 1, (String) data);
		} else if (boolean.class.equals(dataCls)) {
			ps.setBoolean(pos + 1, ((Boolean) data));
		} else if (int.class.equals(dataCls)) {
			ps.setInt(pos + 1, (Integer) data);
		} else if (double.class.equals(dataCls)) {
			ps.setDouble(pos + 1, (Double) data);
		} else if (Date.class.equals(dataCls)) {
			Date val = (Date) data;
			ps.setTimestamp(pos + 1, new Timestamp(val.getTime()));
		} else if (BigDecimal.class.equals(dataCls)) {
			ps.setBigDecimal(pos + 1, (BigDecimal) data);
		} else {
			// 未知类型
			ps.setObject(pos + 1, data);
		}

	}

	private static Type[] getParamTypes(List params) {
		List paramTypes = new ArrayList();

		for (Iterator i = params.iterator(); i.hasNext();) {
			Object param = (Object) i.next();
			// paramTypes.add(TypeFactory.heuristicType(param.getClass().getName()));//zhaomc
			// delete
			paramTypes.add(new TypeResolver().heuristicType(param.getClass().getName()));// zhaomc
			// add
			// 3.5以上
			// 但是总
			// new
		}

		return ArrayHelper.toTypeArray(paramTypes);
	}

	protected Serializable getKey(Serializable bean) {
		return null;
	}

	public void updateNotNullBean(Serializable bean) throws BizException {
		Serializable key = getKey(bean);
		if (key == null)
			throw new BizException("dao未设置主键");
		Object newBean = findById(key);
		CopyUtil.copyNotNullProperties(newBean, bean);
		update(newBean);

	}

	public void updateNotNullBean(Serializable bean, Serializable key) throws BizException {
		if (key == null)
			throw new BizException("dao未设置主键");
		Object newBean = findById(key);
		CopyUtil.copyNotNullProperties(newBean, bean);
		update(newBean);

	}
}
